﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Microsoft.Office.Interop.Excel;
using Excel = Microsoft.Office.Interop.Excel;
using System.Reflection;

namespace OptimumSolution
{
    public partial class Main : Form
    {
        private bool isOpen = false;
        private Excel.Application app;
        private String excelPath = "";
        private Workbook workbook;
        private Sheets sheets;
        private int row;
        private int col;

        public Main()
        {
            InitializeComponent();
        }

        private bool InitWorkbook(String excelpath)
        {
            try
            {
                app = new Excel.Application
                {
                    Visible = false,
                    DisplayAlerts = false
                };
                workbook = app.Workbooks.Open(excelpath, Missing.Value, Missing.Value, Missing.Value, Missing.Value,
                Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value,
                Missing.Value, Missing.Value, Missing.Value, Missing.Value);
                sheets = workbook.Sheets;
                Worksheet sheet = (Worksheet)sheets[1];
                row = sheet.UsedRange.Rows.Count;
                col = sheet.UsedRange.Columns.Count;
                isOpen = true;
                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error");
                return false;
            }
        }

        private void btnOpen_Click(object sender, EventArgs e)
        {
            openFileDialog.Title = "打开excel文件";
            openFileDialog.Filter = "Excel(*.xlsx)|*.xlsx|Excel(*.xls)|*.xls";
            openFileDialog.Multiselect = false;
            openFileDialog.InitialDirectory = @"Desktop";
            openFileDialog.RestoreDirectory = true;

            if (isOpen)
            {
                isOpen = false;
                workbook.Close(false, Missing.Value, Missing.Value);//关闭打开的表
                System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook);
                workbook = null;
                app.Workbooks.Close();
                app.Quit();
                app = null;
                System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
                GC.Collect();//系统回收资源
                GC.WaitForPendingFinalizers();
            }

            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                if (string.IsNullOrEmpty(openFileDialog.FileName))
                {
                    MessageBox.Show("文件打开失败！");
                    return;
                }

                labelFile.Text = excelPath = "File: " + openFileDialog.FileName;

                InitWorkbook(openFileDialog.FileName);
            }
        }

        private void BtnGo_Click(object sender, EventArgs e)
        {
            if (excelPath == "")
            {
                MessageBox.Show("未打开Excel文件！");
                return;
            }

            if(tbInput.Text == "")
            {
                MessageBox.Show("未输入参数！");
                return;
            }
            
            if(!isOpen)
            {
                InitWorkbook(excelPath);
            }
            int errorRow = 0;
            try
            {
                String[] strPinbanSum = tbInput.Text.Trim().Split(',');
                int[] pinBanSum = Array.ConvertAll<string, int>(strPinbanSum, delegate (string s) { return int.Parse(s); });
                
                Worksheet sheet = (Worksheet)sheets[1];

                sheet.Cells[1, 2] = "拼版数";
                sheet.Cells[1, 3] = "张数";
                
                Range dataRange = sheet.Range[sheet.Cells[2, 1], sheet.Cells[row, col]];

                object[,] dataObject = new object[row, col];
                dataObject = (object[,])dataRange.Value;
                object[,] resultObject = new object[row - 1, 2];

                List<int> dataList = new List<int>();

                for (int i = 1; i <= row; i++)
                {
                    errorRow = i;
                    if (i == row || dataObject[i, 1] == null)
                    {
                        List<int> result = GetOptimumSolution(pinBanSum, dataList.ToArray());
                        if (result != null)
                        {
                            int k = result.Count - 1;
                            for (int j = i - 1; j > i - dataList.Count - 1; j--)
                            {
                                resultObject[j - 1, 0] = result[k--];
                                resultObject[j - 1, 1] = result[0];
                            }   
                        }
                        if (i == row)
                        {
                            break;
                        }
                        dataList = new List<int>();
                        while (dataObject[i, 1] == null)
                        {
                            i++;
                        }
                        i--;
                        continue;
                    }
                    dataList.Add(Convert.ToInt32(dataObject[i, 1]));
                }
                
                Range resultRange = sheet.Range[sheet.Cells[2, 2], sheet.Cells[row, 3]];
                resultRange.Value2 = resultObject;

                workbook.Save();
                //int[] data = { 42, 34, 148, 263, 240, 123, 65, 44 };
                //int[] bankuai = { 24, 48, 72 };
                //List<int> result = GetOptimumSolution(bankuai, data);
                MessageBox.Show("收工！");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + " " + Convert.ToString(errorRow));
            }
            finally
            {
                if (isOpen)
                {
                    isOpen = false;
                    workbook.Close(false, Missing.Value, Missing.Value);//关闭打开的表
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook);
                    workbook = null;
                    app.Workbooks.Close();
                    app.Quit();
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
                    app = null;
                    GC.Collect();//系统回收资源
                    GC.WaitForPendingFinalizers();
                }
            }
            
        }

        public static List<int> GetOptimumSolution(int[] pinbanSum, int[] data)
        {

            int length1 = pinbanSum.Length;
            Dictionary<int, List<int>> dataMap = new Dictionary<int, List<int>>();
            List<int> result = null;

            for (int j = 0; j < length1; j++)
            {
                if (pinbanSum[j] < data.Length)
                {
                    continue;
                }
                int sum = 0;
                int length = data.Length;
                for (int i = 0; i < length; i++)
                {
                    sum = sum + data[i];
                }
                Console.WriteLine(sum);
                // 所有的数据的平均数,最少张数
                int avg = sum / pinbanSum[j] + 1;
                Console.WriteLine("最少张数：" + avg);

                int[] b = new int[length];
                int sumB = 0;
                int flag = 0;
                Console.WriteLine("计算板块数：");
                while (flag == 0 || sumB == length)
                {
                    sumB = 0;
                    for (int i = 0; i < length; i++)
                    {
                        b[i] = data[i] / avg + 1;
                    }
                    for (int i = 0; i < length; i++)
                    {
                        sumB = sumB + b[i];
                        Console.Write(b[i] + " ");
                    }
                    Console.WriteLine();
                    Console.WriteLine("张数：" + avg);
                    Console.WriteLine("板块总数：" + sumB);

                    if (sumB <= pinbanSum[j])
                    {
                        break;
                    }
                    avg++;
                }

                // 差值
                Console.WriteLine("\n开始计算差值：");
                int cha = pinbanSum[j] - sumB;
                while (cha != 0)
                {
                    Console.WriteLine("板块数与目标数相差：" + cha);
                    Console.WriteLine("各个差值：");
                    int[] chazhi = new int[length];
                    for (int i = 0; i < length; i++)
                    {
                        chazhi[i] = b[i] * avg - data[i];
                        Console.Write(chazhi[i] + " ");
                    }
                    Console.WriteLine();

                    // 得到最低值，最低值的板块数加一
                    int min = chazhi[0];
                    int minIndex = 0;
                    for (int i = 1; i < length; i++)
                    {
                        if (min > chazhi[i])
                        {
                            min = chazhi[i];
                            minIndex = i;
                        }
                    }
                    b[minIndex]++;// 最小差值对应的板块数加一

                    // 比较板块总数与目标值
                    sumB = 0;
                    Console.WriteLine("板块数：");
                    for (int i = 0; i < length; i++)
                    {
                        sumB = sumB + b[i];
                        Console.Write(b[i] + " ");
                    }
                    Console.WriteLine();
                    Console.WriteLine("板块总数：" + sumB);

                    cha = pinbanSum[j] - sumB;
                }

                Console.WriteLine();
                Console.WriteLine("最后结果：\n张数：" + avg);
                Console.WriteLine("板块数：");
                for (int i = 0; i < length; i++)
                {
                    sumB = sumB + b[i];
                    Console.Write(b[i] + " ");
                }
                Console.WriteLine();
                Console.WriteLine();

                result = new List<int>();
                result.Add(avg);
                for (int i = 0; i < b.Length; i++)
                {
                    result.Add(b[i]);
                }
                dataMap.Add(pinbanSum[j], result);

            }

            int a = 0;// 张数与板块总数的乘积
            int a1 = 0;// 板块总数

            foreach (int key in dataMap.Keys)
            {
                List<int> value = dataMap[key];

                if (a == 0 || a > key * value[0])
                {
                    a = key * value[0];
                    a1 = key;
                }
            }

            if (dataMap.Count == 0)
            {
                return null;
            }

            Console.WriteLine("\n最优解：");
            Console.WriteLine("拼版总数：{0}", a1);
            Console.WriteLine("张数：{0}", dataMap[a1][0]);
            Console.WriteLine("拼版数：");
            for (int i = 1; i < dataMap[a1].Count; i++)
            {
                Console.Write(dataMap[a1][i] + " ");
            }
            Console.WriteLine();

            return dataMap[a1];

        }

    }
}
